package com.moonshineproject.text
{
	import com.moonshineproject.utils.TextUtil;
	import com.moonshineproject.vo.Settings;
	
	import flash.events.EventDispatcher;

	public class TextEditorModel extends EventDispatcher
	{
		private var _selectedLineIndex:int = 0;
		private var _caretIndex:int;
		
		public var itemRenderersInUse:Vector.<TextLineRenderer> = new Vector.<TextLineRenderer>();
		public var itemRenderersFree:Vector.<TextLineRenderer> = new Vector.<TextLineRenderer>();
		
		public var lines:Vector.<TextLineModel> = new Vector.<TextLineModel>();
		
		// Vertical scrolling, in lines.
		public var scrollPosition:int = 0;
		public var renderersNeeded:int = 0;
		
		// Horizontal scrolling, in pixels.
		public var horizontalScrollPosition:int = 0;
		public var width:Number = 0;
		
		public function set selectedLineIndex(idx:int):void
		{
			_selectedLineIndex = idx;
			validateSelection();
		}
		public function get selectedLineIndex():int
		{
			return _selectedLineIndex;
		}
		
		public function set caretIndex(idx:int):void
		{
			// Get current line indentation
			var indent:int = selectedLine ? TextUtil.indentAmount(selectedLine.text) : 0;
			
			// Store the index with tabs expanded
			_caretIndex = idx + Math.min(indent, idx) * (Settings.font.tabWidth - 1);
			
			validateSelection();
		}
		public function get caretIndex():int
		{
			if (selectedLine)
			{
				// Get current line indentation
				var indent:int = TextUtil.indentAmount(selectedLine.text);
				// Get the index with tabs contracted
				var idx:int = _caretIndex - indent * (Settings.font.tabWidth - 1);
				// If the index falls within the indentation, approximate
				if (idx <= indent) idx = Math.round(_caretIndex / Settings.font.tabWidth);
				
				// Limit the index by the line length
				return Math.min(idx, selectedLine.text.length);
			}
			
			return 0;
		}
		
		public var selectionStartLineIndex:int = -1;
		public var selectionStartCharIndex:int = -1;
		
		public function get hasMultilineSelection():Boolean
		{
			return selectionStartLineIndex > -1 && selectedLineIndex != selectionStartLineIndex;
		}
		
		public function get hasSelection():Boolean
		{
			return selectionStartCharIndex != -1;
		}
		
		public function removeSelection():void
		{
			selectionStartLineIndex = -1;
			selectionStartCharIndex = -1;
		}
		
		public function setSelection(startLine:int, startChar:int, endLine:int, endChar:int):void
		{
			selectionStartLineIndex = startLine;
			selectionStartCharIndex = startChar;
			_selectedLineIndex = endLine;
			caretIndex = endChar; // This triggers validation
		}
		
		public function isLineVisible(lineIndex:int):Boolean
		{
			if (lineIndex < scrollPosition) return false;
			if (lineIndex > scrollPosition+renderersNeeded) return false;
			
			return true;
		}
		
		public function get selectedLine():TextLineModel
		{
			return selectedLineIndex >= 0 && selectedLineIndex < lines.length ? lines[selectedLineIndex] : null;
		}
		
		private function validateSelection():void
		{
			if (selectionStartCharIndex == caretIndex && selectionStartLineIndex == selectedLineIndex)
			{
				removeSelection();
			}
		}
	}
}